#pragma once

#include "znx_defs.h"

typedef struct znx_queue_s  znx_queue_t;

struct znx_queue_s {
    znx_queue_t *prev;
    znx_queue_t *next;
};


#define znx_queue_init(q)                                       \
    (q)->prev = q;                                              \
    (q)->next = q


static inline znx_bool_t
znx_queue_inited(znx_queue_t *q)
{
    if (q->prev != NULL || q->next != NULL) {
        return ZNX_TRUE;
    }

    return ZNX_FALSE;
}


#define znx_queue_empty(h)                                      \
    (h == (h)->prev)


#define znx_queue_insert_head(h, x)                             \
    (x)->next = (h)->next;                                      \
    (x)->next->prev = x;                                        \
    (x)->prev = h;                                              \
    (h)->next = x


#define znx_queue_insert_after   znx_queue_insert_head


#define znx_queue_insert_tail(h, x)                             \
    (x)->prev = (h)->prev;                                      \
    (x)->prev->next = x;                                        \
    (x)->next = h;                                              \
    (h)->prev = x


#define znx_queue_head(h)                                       \
    (h)->next


#define znx_queue_last(h)                                       \
    (h)->prev


#define znx_queue_sentinel(h)                                   \
    (h)


#define znx_queue_next(q)                                       \
    (q)->next


#define znx_queue_prev(q)                                       \
    (q)->prev



#define znx_queue_remove(x)                                     \
    (x)->next->prev = (x)->prev;                                \
    (x)->prev->next = (x)->next;                                \
    (x)->prev = NULL;                                           \
    (x)->next = NULL


#define znx_queue_split(h, q, n)                                \
    (n)->prev = (h)->prev;                                      \
    (n)->prev->next = n;                                        \
    (n)->next = q;                                              \
    (h)->prev = (q)->prev;                                      \
    (h)->prev->next = h;                                        \
    (q)->prev = n;


#define znx_queue_add(h, n)                                     \
    (h)->prev->next = (n)->next;                                \
    (n)->next->prev = (h)->prev;                                \
    (h)->prev = (n)->prev;                                      \
    (h)->prev->next = h;


#define znx_queue_data(q, type, link)                           \
    (type *) ((char *) q - offsetof(type, link))


znx_queue_t *znx_queue_middle(znx_queue_t *queue);
void znx_queue_sort(znx_queue_t *queue,
    int (*cmp)(const znx_queue_t *, const znx_queue_t *));

// move src elements to dest head
void znx_queue_move(znx_queue_t *src, znx_queue_t *dest);

